#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>
#include <unistd.h>

using namespace std;

#define THREAD_NUM 4
typedef void(*func_t)(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond);


int tickets = 1000;

class ThreadData
{
public:
	ThreadData(const string& tname, func_t func, pthread_mutex_t* mtx, pthread_cond_t* cond)
		:_tname(tname)
		, _mtx(mtx)
		, _cond(cond)
		, _func(func)
	{}

public:
	string _tname;
	func_t _func;
	pthread_mutex_t* _mtx;
	pthread_cond_t* _cond;
};

void func1(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
	while (true)
	{
		pthread_mutex_lock(mtx);

		pthread_cond_wait(cond, mtx);
		cout << "new thread: " << "--a\n";

		pthread_mutex_unlock(mtx);
	}
}

void func2(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
	while (true)
	{
		pthread_mutex_lock(mtx);

		pthread_cond_wait(cond, mtx);
		cout << "new thread: " << "--b\n";

		pthread_mutex_unlock(mtx);
	}
}

void func3(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
	while (true)
	{
		pthread_mutex_lock(mtx);

		pthread_cond_wait(cond, mtx);
		cout << "new thread: " << "--c\n";

		pthread_mutex_unlock(mtx);
	}
}

void func4(const string& name, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
	while (true)
	{
		pthread_mutex_lock(mtx);

		pthread_cond_wait(cond, mtx);
		cout << "new thread: " << "--d\n";

		pthread_mutex_unlock(mtx);
	}
}

void* Entry(void* args)
{
	ThreadData* td = (ThreadData*)args;
	cout << td->_tname << ":";
	td->_func(td->_tname, td->_mtx, td->_cond);

	delete td;
}

int main()
{
	pthread_mutex_t mtx;
	pthread_cond_t cond;
	pthread_t tid[THREAD_NUM];
	func_t func[THREAD_NUM] = { func1, func2, func3, func4 };

	pthread_mutex_init(&mtx, nullptr);
	pthread_cond_init(&cond, nullptr);

	for (int i = 0; i < THREAD_NUM; i++)
	{
		string name("thread: ");
		name += to_string(i + 1);
		ThreadData* td = new ThreadData(name, func[i], &mtx, &cond);
		pthread_create(tid + i, nullptr, Entry, (void*)td);
	}

	while (true)
	{
		pthread_cond_broadcast(&cond);
		sleep(1);
	}


	for (int i = 0; i < THREAD_NUM; i++)
	{
		pthread_join(tid[i], nullptr);
	}

	pthread_mutex_destroy(&mtx);
	pthread_cond_destroy(&cond);

	return 0;
}